/*
 * ProtocolParser.cpp
 *
 *  Created on: Sep 7, 2017
 *      Author: guoxs
 */
#include <vector>
#include <string.h>
#include <system/Mutex.h>
#include "CommDef.h"
#include "uart/ProtocolParser.h"
#include "utils/Log.h"

static Mutex sLock;
static std::vector<OnProtocolDataUpdateFun> sProtocolDataUpdateListenerList;

void registerProtocolDataUpdateListener(OnProtocolDataUpdateFun pListener)
{
   Mutex::Autolock _l(sLock);
   LOGD("registerProtocolDataUpdateListener\n");
   if (pListener != NULL)
   {
      sProtocolDataUpdateListenerList.push_back(pListener);
   }
}

void unregisterProtocolDataUpdateListener(OnProtocolDataUpdateFun pListener)
{
   Mutex::Autolock _l(sLock);
   LOGD("unregisterProtocolDataUpdateListener\n");
   if (pListener != NULL)
   {
      std::vector<OnProtocolDataUpdateFun>::iterator iter = sProtocolDataUpdateListenerList.begin();
      for (; iter != sProtocolDataUpdateListenerList.end(); iter++)
      {
         if ((*iter) == pListener)
         {
            sProtocolDataUpdateListenerList.erase(iter);
            return;
         }
      }
   }
}

static void notifyProtocolDataUpdate(const SProtocolData &data)
{
   Mutex::Autolock _l(sLock);
   std::vector<OnProtocolDataUpdateFun>::const_iterator iter = sProtocolDataUpdateListenerList.begin();
   for (; iter != sProtocolDataUpdateListenerList.end(); iter++)
   {
      (*iter)(data);
   }
}

static SProtocolData sProtocolData;

SProtocolData &getProtocolData()
{
   return sProtocolData;
}

/**
 * 获取校验码
 * Get checksum code
 */
BYTE getCheckSum(const BYTE *pData, int len)
{
   int sum = 0;
   for (int i = 0; i < len; ++i)
   {
      sum += pData[i];
   }

   return (BYTE)(~sum + 1);
}

/**
 * 解析每一帧数据
 * Parse each frame of data
 */
static void procParse(const BYTE *pData, UINT len)
{
   // CmdID
   switch (MAKEWORD(pData[3], pData[2]))
   {
   case CMDID_POWER:
      sProtocolData.power = pData[5];
      break;
   }

   // 通知协议数据更新
   // Notify protocol data update
   notifyProtocolDataUpdate(sProtocolData);
}

/**
 * 功能：解析协议
 * Function: Parse protocol
 * 参数：pData 协议数据，len 数据长度
 * Parameters: pData - protocol data, len - data length
 * 返回值：实际解析协议的长度
 * Return value: the length of the actual resolution protocol
 */
int parseProtocol(const BYTE *pData, UINT len)
{
   UINT remainLen = len; // 剩余数据长度 Remaining data length
   UINT dataLen;         // 数据包长度 Packet length
   UINT frameLen;        // 帧长度 Frame length

   /**
    * 以下部分需要根据协议格式进行相应的修改，解析出每一帧的数据
    * The following parts need to be modified according to the protocol format to parse out the data of each frame
    */
   while (remainLen >= DATA_PACKAGE_MIN_LEN)
   {
      // 找到一帧数据的数据头
      // Find the data header of a frame of data
      while ((remainLen >= 2) && ((pData[0] != CMD_HEAD1) || (pData[1] != CMD_HEAD2)))
      {
         pData++;
         remainLen--;
         continue;
      }

      if (remainLen < DATA_PACKAGE_MIN_LEN)
      {
         break;
      }

      dataLen = pData[4];
      frameLen = dataLen + DATA_PACKAGE_MIN_LEN;
      if (frameLen > remainLen)
      {
         // 数据内容不全
         // Incomplete data packet
         break;
      }

      // 打印一帧数据，需要时在CommDef.h文件中打开DEBUG_PRO_DATA宏
      // To print a data of frame, open the DEBUG_PRO_DATA macro in the CommDef.h file when needed
#ifdef DEBUG_PRO_DATA
      for (UINT i = 0; i < frameLen; ++i)
      {
         LOGD("%x ", pData[i]);
      }
      LOGD("\n");
#endif

      // 支持checksum校验，需要时在CommDef.h文件中打开PRO_SUPPORT_CHECK_SUM宏
      // Support checksum verification, open the PRO_SUPPORT_CHECK_SUM macro in CommDef.h file when needed
#ifdef PRO_SUPPORT_CHECK_SUM
      // 检测校验码 Checksum
      if (getCheckSum(pData, frameLen - 1) == pData[frameLen - 1])
      {
         // 解析一帧数据
         // Parse a data of frame
         procParse(pData, frameLen);
      }
      else
      {
         LOGE("CheckSum error!!!!!!\n");
      }
#else
      // 解析一帧数据
      // Parse a data of frame
      procParse(pData, frameLen);
#endif

      pData += frameLen;
      remainLen -= frameLen;
   }

   return len - remainLen;
}

// SynchFrame CmdID  DataLen Data CheckSum (可选)
// SynchFrame CmdID DataLen Data CheckSum (optional)
/*     2Byte  2Byte   1Byte	N Byte  1Byte */
// Minimum length with CheckSum: 2 + 2 + 1 + 1 = 6
// 有CheckSum情况下最小长度: 2 + 2 + 1 + 1 = 6
// Minimum length without CheckSum: 2 + 2 + 1 = 5
// 无CheckSum情况下最小长度: 2 + 2 + 1 = 5

/**
 * 解析每一帧数据
 * Parse each frame of data
 */
static void User_procParse(const BYTE *pData, UINT len)
{
   sProtocolData.len = len;
   for (UINT i = 0; i < len; ++i)
   {
      sProtocolData.data[i] = pData[i];
   }

   // 通知协议数据更新
   // Notify protocol data update
   notifyProtocolDataUpdate(sProtocolData);
}

/**
 * 功能：解析协议
 * Function: Parse protocol
 * 参数：pData 协议数据，len 数据长度
 * Parameters: pData - protocol data, len - data length
 * 返回值：实际解析协议的长度
 * Return value: the length of the actual resolution protocol
 */
int User_parseProtocol(const BYTE *pData, UINT len)
{
   UINT remainLen = len; // 剩余数据长度 Remaining data length
   UINT dataLen;         // 数据包长度 Packet length
   UINT frameLen;        // 帧长度 Frame length

   for (UINT i = 0; i < remainLen; i++)
   {
//      LOGD("%d = 0x%x ", len,pData[i]);
      LOGD("%c",pData[i]);
   }

   /**
    * 以下部分需要根据协议格式进行相应的修改，解析出每一帧的数据
    * The following parts need to be modified according to the protocol format to parse out the data of each frame
    */
   while (remainLen >= User_DATA_PACKAGE_MIN_LEN)
   {
      // 找到一帧数据的数据头
      // Find the data header of a frame of data
      while ((remainLen >= 9) && ((pData[0] != User_RX_CMD_HEAD1) || (pData[1] != User_RX_CMD_HEAD2) || ((pData[2] != User_RX_CMD_HEAD3) && (pData[2] != User_RX_CMD_HEAD5)) || (pData[3] != User_RX_CMD_HEAD4)))
      //    		  (pData[2] != User_RX_CMD_HEAD5) || (pData[3] != User_RX_CMD_HEAD4)))
      {
         pData++;
         remainLen--;
         continue;
      }

      if (remainLen < User_DATA_PACKAGE_MIN_LEN)
      {
         break;
      }

      dataLen = pData[4];
      frameLen = dataLen + User_DATA_PACKAGE_MIN_LEN - 7;
      if (frameLen > remainLen)
      {
         // 数据内容不全
         // Incomplete data packet
         break;
      }

      // 打印一帧数据，需要时在CommDef.h文件中打开DEBUG_PRO_DATA宏
      // To print a data of frame, open the DEBUG_PRO_DATA macro in the CommDef.h file when needed
#ifdef User_DEBUG_PRO_DATA
      for (UINT i = 0; i < frameLen; ++i)
      {
         LOGD("%x ", pData[i]);
      }
      LOGD("\n");
#endif

      // 支持checksum校验，需要时在CommDef.h文件中打开PRO_SUPPORT_CHECK_SUM宏
      // Support checksum verification, open the PRO_SUPPORT_CHECK_SUM macro in CommDef.h file when needed
#ifdef User_PRO_SUPPORT_CHECK_SUM
      // 检测校验码 Checksum
      if (getCheckSum(pData, frameLen - 1) == pData[frameLen - 1])
      {
         // 解析一帧数据
         // Parse a data of frame
         procParse(pData, frameLen);
      }
      else
      {
         LOGE("CheckSum error!!!!!!\n");
      }
#else
      // 解析一帧数据
      // Parse a data of frame
      User_procParse(pData, frameLen);
#endif

      pData += frameLen;
      remainLen -= frameLen;
   }

   return len - remainLen;
}
